/**
 * File containing all the Model classes
 */

/**
 * Basic model element
 * @type {omplusClass}
 */
Omplus.models.Element = Omplus.base.extend(Omplus.base.Base, {
    /**
     * Basic init function
     */
    init:function () {
        if (this.controller) {
            var helper;
            var functionName;
            var controller = Omplus.globals.getObject(this.controller);
            for (var i in this.events) {
                var options = {
                    omplusName:this.omplusName + "." + this.events[i],
                    sender:this.omplusName
                };
                helper = Omplus.base.create(Omplus.events[this.events[i]], options);
                functionName = this.events[i].charAt(0).toLowerCase() + this.events[i].slice(1);
                helper.attach(controller[functionName]);
            }
            Omplus.globals.getObject(this.omplusName + ".OnCreateModel").notify([this.controller, this.synchroniseWith]);
        }
    },

    destroy:function () {
    },

    /**
     * Defining omplusType
     */
    omplusType:"Element",

    controller:null,

    synchroniseWith : null,
    validateWith : null,

    /**
     * Value of the element
     */
    value:null,

    /**
     * Defining if the value of the class can be null
     */
    nullable:true,

    events:["OnCreateModel", "OnDestroyModel", "OnUpdateModel", "OnErrorModel"],

    getSynchroniseWith:function () {
        return this.synchroniseWith;
    },
    /**
     * Returns the value
     */
    getValue:function () {
    },

    /**
     * Sets value
     * @param newValue
     */
    setValue:function (newValue, sender) {
    },

    /**
     * Returns nullable
     * @return {Boolean}
     */
    isRequired:function () {
        return !this.nullable;
    }
});

/**
 * Class defining a single element
 * @type {*}
 */
Omplus.models.SingleElement = Omplus.base.extend(Omplus.models.Element, {
    init:function () {
        if (!this.nullable) {
            this.validators.push("EmptyValidator");
        }
        if (this.validateWith != null) {
            this.validators.push("SynchronizeValidator");
        }
        if (this.minimum != null) {
            this.validators.push("MinimumLengthValidator");
        }
        if (this.maximum != null) {
            this.validators.push("MaximumLengthValidator");
        }
        for (var validator in this.validators) {
            var options = {
                omplusName:this.omplusName + "." + this.validators[validator]
            };
            if (this.validators[validator] == "SynchronizeValidator"){
                options.validateWith = this.validateWith
            }
            if (this.validators[validator] == "MinimumLengthValidator"){
                options.minimum = this.minimum
            }
            if (this.validators[validator] == "MaximumLengthValidator"){
                options.maximum = this.maximum
            }
            Omplus.base.create(Omplus.validators[this.validators[validator]], options);
        }
    },
    omplusType:"SingleElement",
    validators:[],
    validateWith : null,
    errors:[],
    destroy:function () {
        if (this.controller)
            Omplus.globals.getObject(this.omplusName + ".OnDestroyModel").notify(this.controller);
        for (var i in this.events) {
            delete Omplus.globals.objects[this.omplusName + "." + this.events[i]];
        }
        for (var i in this.validators) {
            delete Omplus.globals.objects[this.omplusName + "." + this.validators[i]];
        }
        delete Omplus.globals.objects[this.omplusName];
    },
    getValue:function () {
        return this.value;
    },

    setValue:function (newValue, view) {
        if (newValue != null && !newValue.length && typeof(newValue)=='string') newValue = null;
        if (newValue == "None") newValue = null;
        this.value = newValue;
        var valid = this.isValid();
        if (!valid) {
            if (view) {
                for (var error in this.errors) {
                    Omplus.globals.getObject(this.omplusName + ".OnErrorModel").notify([this.controller, view, this.errors[error]]);
                }
            }
        }
        if (this.controller)
            Omplus.globals.getObject(this.omplusName + ".OnUpdateModel").notify([this.controller, view, valid]);
    },
    /**
     * Goes through all validators associated with this element and does validity checks
     * @return {Boolean}
     */
    isValid:function () {
        this.errors = [];
        var valid = true;
        var singleValidator;
        for (var validator in this.validators) {
            singleValidator = Omplus.globals.getObject(this.omplusName + "." + this.validators[validator]);
            if (!singleValidator.isValid(this.getValue())) {
                valid = false;
                this.errors.push(singleValidator.getError());
            }
        }
        return valid;
    },
    showErrors:function () {
        if (!this.isValid()) {
            for (var error in this.errors) {
                Omplus.globals.getObject(this.omplusName + ".OnErrorModel").notify([this.controller, null, this.errors[error]]);
            }
        }
    },
    empty : function(){
    	this.value = null;
    	if (this.controller)
            Omplus.globals.getObject(this.omplusName + ".OnUpdateModel").notify([this.controller, null, true]);
    }
});

/**
 * Class defining a multiple element that contains multiple single elements
 * @type {*}
 */
Omplus.models.MultiElement = Omplus.base.extend(Omplus.models.Element, {

    /**
     * For every Element (Single or Multi) in this MultiElement if that SingleElement isn't omplusClass
     * it creates omplusClass from it, or if its an already created Element it adds its reference to the list
     */
    init:function () {
        for (var i in this.value) {
            if (typeof this.value[i] == Omplus.constants.object && (!this.value[i].isOmplus || this.value[i].isOmplus == Omplus.constants.undefined)) {
                this.value[i].omplusName = this.omplusName + "." + i;
                this.value[i].controller = this.controller;
                this.value[i] = Omplus.base.create(Omplus.models[this.value[i].omplusType], this.value[i]);
            } else if (typeof this.value[i] == Omplus.constants.string) {
                if (typeof Omplus.globals.getObject(this.value[i]) == Omplus.constants.undefined)
                    console.error('You have to create an object with global name "' + this.value[i] + '" before using it.');
                else this.value[i] = Omplus.globals.getObject(this.value[i]);
            }
        }
    },
    omplusType:"MultiElement",

    proxy:null,

    destroy:function () {
        for (var i in this.value) {
            if (this.value[i])
                this.value[i].destroy();
        }
        if (this.controller)
            Omplus.globals.getObject(this.omplusName + ".OnDestroyModel").notify(this.controller);
        for (var i in this.events) {
            delete Omplus.globals.objects[this.omplusName + "." + this.events[i]];
        }
        for (var i in this.validators) {
            delete Omplus.globals.objects[this.omplusName + "." + this.validators[i]];
        }
        delete Omplus.globals.objects[this.omplusName];
    },

    /**
     * Retuns an object filled with the values of this MultipleElement's SingleElements
     * @return {Object}
     */
    getValue:function () {
        var object = new Object();
        for (var i in this.value) {
            object[i] = this.value[i].getValue();
        }
        return object;
    },
    toJSON:function () {
        return JSON.stringify(this.getValue());
    },
    setValue:function (newValue, view) {
        for (var i in newValue) {
            if (this.value[i])
                this.value[i].setValue(newValue[i], view);
        }
        if (this.controller)
            Omplus.globals.getObject(this.omplusName + ".OnUpdateModel").notify([this.controller, view, this.isValid()]);
    },
    isValid:function () {
        var valid = true;
        for (var i in this.value) {
            if (this.value[i])
                if (!this.value[i].isValid()) valid = false;
        }
        return valid;
    },
    showErrors:function () {
        for (var i in this.value) {
            this.value[i].showErrors();
        }
    }
});